import { defineComponent, reactive, onMounted, onUnmounted, provide, watchEffect, createVNode } from 'vue';
import { scrollTop } from '../utils/assist.js';
import AnchorLink from './AnchorLink.js';

const Anchor = /* @__PURE__ */ defineComponent({
  name: 'Anchor',
  props: {
    container: {
      type: [String, Object],
      default: undefined
    },
    scrollContainer: {
      type: [String, Object],
      default: undefined
    },
    scrollOffset: {
      type: Number,
      default: undefined
    },
    offsetTop: {
      type: Number,
      default: undefined
    },
    bounds: {
      type: Number,
      default: undefined
    },
    showInk: {
      type: Boolean,
      default: undefined
    },
    mode: {
      type: String,
      default: undefined
    }
  },
  setup(props, {
    slots
  }) {
    let scrollContainer = null;
    let scrollElement = null;
    let wrapperTop = 0;
    const bounds = props.bounds || 5;
    let titlesOffsetArr = [];
    const mode = props.mode ?? 'hash';
    const showInk = props.showInk ?? false;
    const store = reactive({
      inkTop: 0,
      inkHeight: 0,
      currentId: '',
      currentLink: '',
      animating: false,
      links: [],
      upperFirstTitle: true
    });
    const gotoAnchor = (href, e) => {
      e.stopPropagation && e.stopPropagation();
      e.preventDefault && e.preventDefault();
      store.currentLink = href;
      store.currentId = href.replace('#', '');
      handleScrollTo();
      if (mode === 'hash') {
        window.location.hash = href;
      } else {
        const path = window.location.href;
        const search = path.includes('?') ? path.split('?')[1] : '';
        const index = location.hash.indexOf('?');
        const hash = index > -1 ? location.hash.substring(0, index) : location.hash;
        const params = new URLSearchParams(search);
        params.set('_to', href);
        window.history.replaceState({}, '', `${location.pathname}${hash}?${params.toString()}`);
      }
    };
    const handleScrollTo = () => {
      const anchor = document.getElementById(store.currentId);
      const currentLinkElementA = document.querySelector(`a[data-href="${store.currentLink}"]`);
      let offset = props.scrollOffset || 0;
      if (currentLinkElementA) {
        offset = parseFloat(currentLinkElementA.getAttribute('data-scroll-offset'));
      }
      if (!anchor) return;
      const offsetTop = anchor.offsetTop - wrapperTop - offset;
      store.animating = true;
      scrollTop(scrollContainer, scrollElement.scrollTop, offsetTop, 600, () => {
        store.animating = false;
      });
    };
    onMounted(() => {
      init();
      const links = store.links.map(item => {
        return item.href;
      });
      const idArr = links.map(link => {
        return link.split('#')[1];
      });
      idArr.forEach((id, index) => {
        const titleEle = document.getElementById(id);
        if (titleEle) {
          const offset = titleEle.offsetTop - scrollElement.offsetTop;
          if (titlesOffsetArr[index] && titlesOffsetArr[index].offset !== offset) {
            titlesOffsetArr[index].offset = offset;
          }
        }
      });
    });
    const removeListener = () => {
      scrollContainer && scrollContainer.removeEventListener('scroll', handleScroll);
      window.removeEventListener('hashchange', handleHashChange);
    };
    const getContainer = () => {
      scrollContainer = props.container ? typeof props.container === 'string' ? document.querySelector(props.container) : props.container : window;
      scrollElement = props.container ? scrollContainer : document.documentElement || document.body;
    };
    const containerIsWindow = () => scrollContainer === window;
    const init = () => {
      handleHashChange();
      removeListener();
      getContainer();
      wrapperTop = containerIsWindow() ? 0 : scrollElement.offsetTop;
      handleScrollTo();
      scrollContainer.addEventListener('scroll', handleScroll);
      window.addEventListener('hashchange', handleHashChange);
    };
    const handleHashChange = () => {
      let sharpLinkMatch;
      if (mode === 'hash') {
        const url = window.location.href;
        sharpLinkMatch = /#([^#]+)$/.exec(url);
      } else {
        const path = window.location.href;
        const search = path.includes('?') ? path.split('?')[1] : '';
        const params = new URLSearchParams(search);
        const has = params.has('_to');
        if (has) {
          if (params.get('_to')) {
            sharpLinkMatch = [];
            sharpLinkMatch[0] = params.get('_to');
            sharpLinkMatch[1] = params.get('_to')?.replace('#', '');
          }
        }
      }
      if (!sharpLinkMatch) {
        setTimeout(() => {
          const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
          getCurrentScrollAtTitleId(scrollTop);
        }, 10);
        return;
      }
      store.currentLink = sharpLinkMatch[0];
      store.currentId = sharpLinkMatch[1];
    };
    const handleScroll = e => {
      // this.upperFirstTitle = !!this.titlesOffsetArr[0] && e.target.scrollTop < this.titlesOffsetArr[0].offset;
      if (store.animating) return;
      // this.updateTitleOffset();
      const scrollTop = document.documentElement.scrollTop || document.body.scrollTop || e.target.scrollTop;
      getCurrentScrollAtTitleId(scrollTop);
    };
    const getCurrentScrollAtTitleId = scrollTop => {
      let i = -1;
      const len = titlesOffsetArr.length;
      let titleItem = {
        link: '#',
        offset: 0
      };
      scrollTop += bounds;
      while (++i < len) {
        const currentEle = titlesOffsetArr[i];
        const nextEle = titlesOffsetArr[i + 1];
        if (scrollTop >= currentEle.offset && scrollTop < (nextEle && nextEle.offset || Infinity)) {
          titleItem = titlesOffsetArr[i];
          break;
        }
      }
      store.currentLink = titleItem.link;
    };
    const addLink = link => {
      store.links.push(link);
    };
    onUnmounted(() => {
      removeListener();
    });
    provide('CMAnchorContext', {
      gotoAnchor,
      addLink,
      scrollOffset: props.scrollOffset
    });
    watchEffect(() => {
      store.currentLink;
      const currentLinkElementA = document.querySelector(`a[data-href="${store.currentLink}"]`);
      if (!currentLinkElementA) return;
      const elementATop = currentLinkElementA.offsetTop;
      const elementAHeight = currentLinkElementA.getBoundingClientRect().height;
      const offset = elementAHeight / 4;
      const top = elementATop < 0 ? props.offsetTop || 0 : elementATop;
      store.inkTop = top + offset / 2;
      store.inkHeight = elementAHeight * 3 / 4;
    });
    watchEffect(() => {
      const links = store.links.map(item => {
        return item.href;
      });
      const idArr = links.map(link => {
        return link.split('#')[1];
      });
      if (!scrollElement) {
        getContainer();
      }
      const arr = [];
      idArr.forEach(id => {
        const titleEle = document.getElementById(id);
        if (titleEle) arr.push({
          link: `#${id}`,
          offset: titleEle.offsetTop - scrollElement.offsetTop
        });
      });
      titlesOffsetArr = arr;
    });
    return () => createVNode("div", {
      "class": "cm-anchor"
    }, [createVNode("div", {
      "class": "cm-anchor-wrapper"
    }, [createVNode("div", {
      "class": "cm-anchor-inner"
    }, [createVNode("div", {
      "class": "cm-anchor-ink " + (showInk ? 'cm-anchor-show' : '')
    }, [createVNode("span", {
      "class": "cm-anchor-ink-ball",
      "style": {
        top: `${store.inkTop}px`,
        height: `${store.inkHeight}px`
      }
    }, null)]), slots.default?.()])])]);
  }
});
Anchor.Link = AnchorLink;

export { Anchor as default };
